﻿<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <a href="http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/">this in JS</a>
    <div>
        when a function is executed, it gets the <em>this</em> property—a variable with the <strong>value of <em>the object</em> that invokes the function where <em>this</em> is used</strong>.
    </div>
    <h2>Ver problemas en codigo javascript de esta pagina</h2>
</body>
</html>
<script>
    var person = {
        firstName: "Penelope",
        lastName: "Barrymore",
        showFullName: function () {
            // The "context"
            console.log(this.firstName + " " + this.lastName);
        }
    };
    // The "context", when invoking showFullName, is the person object, when we invoke the showFullName () method on the person object.
    // And the use of "this" inside the showFullName() method has the value of the person object,
    person.showFullName(); // Penelope Barrymore

    // If we invoke showFullName with a different object:
    var anotherPerson = {
        firstName: "Rohit",
        lastName: "Khan"
    };

    // We can use the apply method to set the "this" value explicitly—more on the apply () method later.
    // "this" gets the value of whichever object invokes the"this Function", hence:
    person.showFullName.apply(anotherPerson); // Rohit Khan



    /*
    **************
    ***Problems***
    **************
    */

    /*************
    Problema 1: Fix this when used in a method passed as a callback           
    ***************/
    // We have a simple object with a clickHandler method that we want to use when a button on the page is clicked
    var user = {
        data: [{ name: "T. Woods", age: 37 }, { name: "P. Mickelson", age: 43 }],
        clickHandler: function (event) {
            var randomNum = ((Math.random() * 2 | 0) + 1) - 1; // random number between 0 and 1

            // This line is printing a random person's name and age from the data array
            console.log(this.data[randomNum].name + " " + this.data[randomNum].age);
        }
    };

    // The button is wrapped inside a jQuery $ wrapper, so it is now a jQuery object
    // And the output will be undefined because there is no data property on the button object
    $("button").click(user.clickHandler); // Cannot read property '0' of undefined

    //the fix would be
    $("button").click(user.clickHandler.bind(user)); // P. Mickelson 43



    /*************
   Problema 2: Fix this inside closure       
   ***************/
    var user = {
        tournament: "The Masters",
        data: [{ name: "T. Woods", age: 37 }, { name: "P. Mickelson", age: 43 }],
        clickHandler: function () {
            // the use of this.data here is fine, because "this" refers to the user object, and data is a property on the user object.
            this.data.forEach(function (person) {
                // But here inside the anonymous function (that we pass to the forEach method), "this" no longer refers to the user object.
                // This inner function cannot access the outer function's "this"
                console.log("What is This referring to? " + this); //[object Window]
                console.log(person.name + " is playing at " + this.tournament);
                // T. Woods is playing at undefined
                // P. Mickelson is playing at undefined
            });
        }
    };
    user.clickHandler(); // What is This referring to? [object Window]

    //the fix would be store this in outer scope
    // We set the value of "this" to theUserObj variable, so we can use it later
    var theUserObj = this;


    /*************
  Problema 3: Fix this when method is assigned to a variable       
  ***************/
    // This data variable is a global variable
    var data = [{ name: "Samantha", age: 12 }, { name: "Alexis", age: 14 }];

    var user = {
        // this data variable is a property on the user object
        data: [{ name: "T. Woods", age: 37 }, { name: "P. Mickelson", age: 43 }],
        showData: function (event) {
            var randomNum = ((Math.random() * 2 | 0) + 1) - 1; // random number between 0 and 1
            // This line is adding a random person from the data array to the text field
            console.log(this.data[randomNum].name + " " + this.data[randomNum].age);
        }
    };

    // Assign the user.showData to a variable
    var showUserData = user.showData;

    // When we execute the showUserData function, the values printed to the console are from the global data array, not from the data array in the user object
    //
    showUserData(); // Samantha 12 (from the global data array)

    //solution
    // Bind the showData method to the user object
    var showUserData = user.showData.bind(user);



    /*************
  Problema 3: Fix this when borrowing methods     
  ***************/
    // We have two objects. One of them has a method called avg () that the other doesn't have
    // So we will borrow the (avg()) method
    var gameController = {
        scores: [20, 34, 55, 46, 77],
        avgScore: null,
        players: [{ name: "Tommy", playerID: 987, age: 23 }, { name: "Pau", playerID: 87, age: 33 }]
    };

    var appController = {
        scores: [900, 845, 809, 950],
        avgScore: null,
        avg: function () {
            var sumOfScores = this.scores.reduce(function (prev, cur, index, array) {
                return prev + cur;
            });
            this.avgScore = sumOfScores / this.scores.length;
        }
    };

    //If we run the code below,
    // the gameController.avgScore property will be set to the average score from the appController object "scores" array

    // Don't run this code, this is just for illustration; we want the appController.avgScore to remain null
    gameController.avgScore = appController.avg();

    //fix
    // Note that we are using the apply () method, so the 2nd argument has to be an array—the arguments to pass to the appController.avg () method.
    appController.avg.apply(gameController, gameController.scores);

    // The avgScore property was successfully set on the gameController object, even though we borrowed the avg () method from the appController object
    console.log(gameController.avgScore); // 46.4

    // appController.avgScore is still null; it was not updated, only gameController.avgScore was updated
    console.log(appController.avgScore); // null
</script>
